using System;
using System.Collections;
using System.Collections.Generic;
using Script.Library.Ability;
using UnityEngine;

public class Creature : MonoBehaviour
{
	[Header("Data")]
	public float maxHealth;

	[NonSerialized]
	public float speed = 10f;

	[Header("State")]
	public float health;

	public bool meatEater;

	public float size;

	public bool rotationBlock;

	public float speedController = 1f;

	public int startSize;

	public float stamina = 100f;

	public bool swim;

	public bool untouchable;

	public bool webWalker;

	[Header("Requirement")]
	public CapsuleCollider2D capsuleCollider;

	public Carrion carrion;

	public GameObject body;

	public Transform model;

	public Rigidbody2D rigidbody;

	public Transform root;

	public new Transform transform;

	[Header("Body Parts")]
	public Transform head;

	public Animation headAnimation;

	public Animation[] legsAnimation;

	public Animation mouthAnimation;

	public Ability[] abilities;

	public Ability ability;

	public MovementAbility movementAbility;

	private bool isAbilityLocked;

	private Collider2D[] allColliders;

	[HideInInspector]
	public Vector2 currentDirection;

	private int defaultLayer;

	private int pertitentSize;

	[HideInInspector]
	public float poisonResistence = 1f;

	private int poisoningSeverity = -1;

	private Vector2 lastAbilityPosition;

	private bool staminaCharging;

	private bool isPlayingLegsAnimation;

	protected bool swimming;

	private float posZ;

	protected Transform healthBarParent;

	public static GameObject poisonEffect;

	private float animateHeight = -0.8f;

	private uint animateHeightId;

	private void Start()
	{
		SetSize(0f);
		maxHealth = 100 + 50 * GetSize();
		health = maxHealth;
		defaultLayer = body.layer;
		List<Collider2D> list = new List<Collider2D>();
		transform.GetComponentsInChildren(list);
		list.RemoveAt(0);
		allColliders = list.ToArray();
		SetPosition(GetPosition());
	}

	public void ActiveAbility(Ability ability)
	{
		if (ability.IsInUse())
		{
			if (ability.Cancel())
			{
				EndAbility(ability);
			}
		}
		else if ((!isAbilityLocked || ability.priority == 0) && ability.Check())
		{
			lastAbilityPosition = GetPosition();
			ability.Begin();
		}
	}

	public void ActiveAbility(int id)
	{
		ActiveAbility(abilities[id]);
	}

	public void LockAbilities()
	{
		isAbilityLocked = true;
		if (ability != null)
		{
			ActiveAbility(ability);
		}
	}

	public void EndAbility(Ability ability)
	{
		ability.End();
	}

	public void UnlockAbilities()
	{
		isAbilityLocked = false;
	}

	private void AssignLegsAnimation()
	{
		int num = legsAnimation.Length / 2;
		float length = legsAnimation[0]["walk"].length;
		float time = length / 2f;
		int num2;
		int num3 = (num2 = 1);
		for (int i = 0; i < num; i++)
		{
			AnimationState animationState = legsAnimation[num3]["walk"];
			animationState.time = time;
			num3 += num2;
			num2 = (num2 + 2) % 4;
		}
	}

	public void ChangeLegsAnimationSpeed(float speed)
	{
		StartLegsAnimation();
		Animation[] array = legsAnimation;
		foreach (Animation animation in array)
		{
			animation["walk"].speed = speed;
		}
	}

	public void OverwriteAnimation(Animation animation)
	{
		animation.Stop();
		animation.Play();
	}

	public void StartLegsAnimation()
	{
		if (!isPlayingLegsAnimation)
		{
			isPlayingLegsAnimation = true;
			AssignLegsAnimation();
			Animation[] array = legsAnimation;
			foreach (Animation animation in array)
			{
				animation.Play();
			}
		}
	}

	public void StartLegsAnimation(string name)
	{
		Animation[] array = legsAnimation;
		foreach (Animation animation in array)
		{
			if ((bool)animation[name])
			{
				animation.Play(name);
			}
			else
			{
				animation.Stop();
			}
		}
		isPlayingLegsAnimation = false;
	}

	public void StopLegsAnimation()
	{
		if (isPlayingLegsAnimation)
		{
			isPlayingLegsAnimation = false;
			Animation[] array = legsAnimation;
			foreach (Animation animation in array)
			{
				animation.Stop();
			}
		}
	}

	public virtual void PlaySound()
	{
	}

	public void HideBody()
	{
		SetVisibilityOfBody(false);
	}

	public void LiftBody(float height, Ability ability = null)
	{
		StartCoroutine(AnimateLiftingOfTheBody(height, ability));
	}

	private IEnumerator AnimateLiftingOfTheBody(float height, Ability ability)
	{
		uint id = ++animateHeightId;
		Transform transform = root;
		float diffrence = height - animateHeight;
		float duration = diffrence.Abs() / 4f;
		float stage = duration;
		while (stage > 0f)
		{
			stage -= Time.deltaTime;
			animateHeight = height - diffrence * (stage / duration);
			GetLiftingEffect(transform);
			yield return Info.wait;
			if (id != animateHeightId)
			{
				yield break;
			}
		}
		animateHeight = height;
		GetLiftingEffect(transform);
		if (ability != null)
		{
			EndAbility(ability);
		}
	}

	private void GetLiftingEffect(Transform transform)
	{
		Vector3 localPosition = transform.localPosition;
		localPosition.z = animateHeight;
		transform.localPosition = localPosition;
	}

	private void SetVisibilityOfBody(bool visible)
	{
		model.gameObject.SetActive(visible);
	}

	public void ShowBody()
	{
		SetVisibilityOfBody(true);
		StartLegsAnimation();
	}

	public void Move(Vector2 direction)
	{
		currentDirection = direction;
		if (movementAbility != null && movementAbility.IsMovementAvailable())
		{
			movementAbility.Movement();
		}
		direction = currentDirection;
		rigidbody.velocity = direction * (speed * speedController);
		Vector3 position = Vector3.Lerp(model.position, transform.position, 0.25f);
		model.position = position;
		model.rotation = Quaternion.Lerp(model.rotation, transform.rotation, 0.25f);
		if ((bool)healthBarParent)
		{
			position.z -= 1f;
			healthBarParent.position = position;
		}
		if (!rotationBlock && direction.magnitude != 0f)
		{
			Rotate(direction);
		}
	}

	private void Rotate(Vector2 direction)
	{
		float num = Mathf.Atan2(direction.y, direction.x) * 57.29578f;
		rigidbody.rotation = Mathf.LerpAngle(rigidbody.rotation, num + 90f, 0.15f);
	}

	public virtual void Eat(Food food, float size)
	{
		int num = pertitentSize;
		SetHealth(5f * size);
		if (food.poison)
		{
			Poison(6);
		}
		if (num != pertitentSize)
		{
			CreatureController.SendInformationToAggressors(carrion);
		}
		PlaySound();
	}

	public void RestoreDefaultLayer()
	{
		body.layer = defaultLayer;
	}

	private void CreateRemains()
	{
		int num = GetSize() + 3;
		Vector3 position = GetPosition();
		position.z = 0f;
		for (int i = 0; i < num; i++)
		{
			UnityEngine.Object.Instantiate(Info.meat, position, Quaternion.identity).GetComponent<Rigidbody2D>().velocity = Main.RandomNormalizedVector2() * 10f;
		}
	}

	public virtual void Death()
	{
		UnityEngine.Object.Destroy(body);
	}

	public virtual void SetHealth(float value)
	{
		health += value;
		SetSize(value * 0.01f);
		if (health <= 0f)
		{
			if (IsEnemy())
			{
				CreateRemains();
			}
			Death();
		}
		else if (health > maxHealth)
		{
			health = maxHealth;
		}
	}

	public void BeginBlockingMovement()
	{
		speedController = 0f;
		rotationBlock = true;
		rigidbody.bodyType = RigidbodyType2D.Kinematic;
	}

	public void EndBlockingMovement()
	{
		speedController = 1f;
		rotationBlock = false;
		rigidbody.bodyType = RigidbodyType2D.Dynamic;
	}

	private IEnumerator BeginPoisoning(int duration)
	{
		int temp = (int)(6f * poisonResistence);
		int startValue = temp - duration;
		duration = temp;
		WaitForSeconds wait = new WaitForSeconds(1f);
		carrion.food.poison = true;
		GameObject gameObject = UnityEngine.Object.Instantiate(poisonEffect, model);
		for (poisoningSeverity = startValue; poisoningSeverity < duration; poisoningSeverity++)
		{
			yield return wait;
			SetHealth(-10f);
		}
		carrion.food.poison = false;
		poisoningSeverity = -1;
		gameObject.GetComponent<ParticleSystem>().Stop();
		UnityEngine.Object.Destroy(gameObject, 2f);
	}

	public bool IsResistantToPoison(Food food)
	{
		return !food.poison || poisonResistence == 0f;
	}

	public void Poison(int duration)
	{
		if (poisonResistence == 0f)
		{
			return;
		}
		duration = (int)((float)duration * poisonResistence);
		if (poisoningSeverity < 0)
		{
			StartCoroutine(BeginPoisoning(duration));
			return;
		}
		poisoningSeverity -= duration;
		if (poisoningSeverity < 0)
		{
			poisoningSeverity = 0;
		}
	}

	public void DisableRigidbody()
	{
		SetRigidbodyState(false, 16);
	}

	public void EnableAllColliders(bool enable)
	{
		Collider2D[] array = allColliders;
		foreach (Collider2D collider2D in array)
		{
			collider2D.enabled = enable;
		}
	}

	public void EnableRigidbody()
	{
		SetRigidbodyState(true, defaultLayer);
	}

	private void SetRigidbodyState(bool enable, int layer)
	{
		body.layer = layer;
		EnableAllColliders(enable);
	}

	public int GetSize()
	{
		return pertitentSize;
	}

	private void SetSize(float value)
	{
		size = Mathf.Clamp01(size + value);
		pertitentSize = startSize + (int)size;
		float num = size + (float)startSize;
		num = 0.5f * ((!(num < 0f)) ? num : (num * 0.5f));
		posZ = num * -0.726f;
		Transform obj = transform;
		Vector3 localScale = Vector3.one * (1f + num);
		model.localScale = localScale;
		obj.localScale = localScale;
	}

	private IEnumerator ChargeStamina()
	{
		WaitForEndOfFrame wait = new WaitForEndOfFrame();
		float diffrence = 100f;
		staminaCharging = true;
		while (diffrence > 0f)
		{
			yield return wait;
			diffrence = 100f - stamina;
			if (diffrence > 5f)
			{
				diffrence = 5f;
			}
			SetStamina(diffrence * Time.deltaTime);
		}
		staminaCharging = false;
	}

	public virtual void SetStamina(float value)
	{
		stamina += value;
		if (!staminaCharging && stamina < 100f)
		{
			StartCoroutine(ChargeStamina());
		}
	}

	private void Drown()
	{
		SetHealth(-30f);
		SetPosition(lastAbilityPosition);
	}

	public virtual void EnableSwimming(int level)
	{
		swim = true;
		int layer = 14;
		body.layer = layer;
		defaultLayer = layer;
		StartCoroutine(Swimming(0.7f + (float)level * 0.3f));
	}

	private bool IsSwimming()
	{
		return Physics2D.OverlapCircle(GetPosition(), 0.4f, 16);
	}

	private IEnumerator Swimming(float speed)
	{
		while (true)
		{
			yield return Engine.swimmingTester;
			if ((animateHeight == -0.8f || swimming) && IsSwimming() != swimming)
			{
				swimming = !swimming;
				if (swimming)
				{
					LockAbilities();
					LiftBody(0.3f);
					speedController = speed;
					StartLegsAnimation("swim");
				}
				else
				{
					LiftBody(-0.8f);
					StartLegsAnimation();
					speedController = 1f;
					UnlockAbilities();
				}
			}
		}
	}

	public void TryDrown()
	{
		if (!swim && IsSwimming())
		{
			Drown();
		}
	}

	public float GetHalfOfBodySize()
	{
		return capsuleCollider.size.y * 0.5f * model.localScale.x;
	}

	public Vector2 GetNormalizedDirection()
	{
		return (currentDirection.magnitude != 0f) ? (currentDirection * 1000f).normalized : (-(Vector2)model.up);
	}

	public Vector3 GetPosition()
	{
		return model.position;
	}

	public Vector3 GetPositionOfTheEndOfTheBody(float bonus = 0f)
	{
		return model.position + model.up * (GetHalfOfBodySize() + bonus);
	}

	public void SetPosition(Vector3 position)
	{
		Transform obj = transform;
		Vector3 localPosition = new Vector3(position.x, position.y, posZ);
		model.localPosition = localPosition;
		obj.localPosition = localPosition;
	}

	public void SetRotation(float z)
	{
		rigidbody.rotation = z;
		model.rotation = Quaternion.Euler(0f, 0f, z);
	}

	private void OnDestroy()
	{
		CreatureController.WipeAggressorsInformation(carrion);
	}

	public virtual bool IsEnemy()
	{
		return false;
	}
}
